import CryptoJS from "crypto-js";
import { Base64 } from "js-base64";
import { ElMessage } from "element-plus";
import { APP_KEY } from "@/config";

const Aes = {
  name: "aes",
  //解密
  decode: function (str) {
    str = Base64.decode(str);
    const config = this.init();
    const decrypted = CryptoJS.AES.decrypt(str, config.key, {
      iv: config.iv,
      padding: CryptoJS.pad.Pkcs7,
      mode: CryptoJS.mode.CBC
    });

    return CryptoJS.enc.Utf8.stringify(decrypted);
  },
  encode: function (plaintext) {
    const config = this.init();
    const ciphertext = CryptoJS.AES.encrypt(plaintext, config.key, {
      iv: config.iv,
      padding: CryptoJS.pad.Pkcs7,
      mode: CryptoJS.mode.CBC
    });

    return Base64.encode(ciphertext.toString());
  },
  init: function () {
    const key = APP_KEY;
    const mdKey = CryptoJS.MD5(key).toString();
    //秘钥必须是 16、24 或 32 位数
    const aesKey = CryptoJS.enc.Utf8.parse(mdKey.substr(16, 16));
    const aesIv = CryptoJS.enc.Utf8.parse(mdKey.substr(0, 16));

    return {
      key: aesKey,
      iv: aesIv
    };
  }
};

const Safe = {
  decode: function (data: object, message: string) {
    if (!data || (!data.encryption && data.length == 0)) {
      return data;
    }

    if (this.validate(data) == false) {
      ElMessage.error(message ? message : "数据解密失败！");
      return null;
    }

    let that = {};
    switch (data.encryption) {
      case Aes.name:
        that = Aes;
        break;
      default:
        that = Aes;
    }

    const params = that.decode(data.pack);
    try {
      return JSON.parse(params);
    } catch (e) {
      ElMessage.error("非法数据！");
      return null;
    }
  },

  encode: function (data: object) {
    const params = {};
    params.encryption = Aes.name;
    params.pack = Aes.encode(JSON.stringify(data));
    params.timestamp = this.timestamp();
    params.sign = this.sign(params);
    return params;
  },

  timestamp: function () {
    const timestamp = new Date().getTime();
    return parseInt(timestamp / 1000);
  },

  sign: function (data) {
    data.key = Aes.init().key.toString(CryptoJS.enc.Utf8);
    const string = this.getArrToString(data);
    delete data.key;
    return CryptoJS.MD5(string).toString();
  },
  validate: function (data: object) {
    const sign = data.sign;
    delete data.sign;
    return sign == this.sign(data);
  },
  /**
   * @var 将数据用 splitter 切割 转化为字符串
   * @param data
   * @param splitter
   * @returns {string}
   */
  getArrToString: function (data: object, splitter) {
    splitter = splitter ? splitter : "&";
    const arr = Object.keys(data).sort();
    const result = {};
    for (let index in arr) {
      const key = arr[index];
      result[key] = data[key];
    }
    let str = "";
    for (let index in result) {
      str += "" + index + "=" + data[index] + splitter;
    }

    str = str.substr(0, str.length - 1);
    return str;
  }
};

export default Safe;
